package mspbots.cw.client.core.data.subdata;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.client.core.AbstractToolsUtil;
import mspbots.cw.client.core.data.BaseSyncService;
import mspbots.cw.client.core.client.ClientProperties;
import mspbots.cw.common.*;
import mspbots.cw.common.subdata.SubDataType;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;


/**
 * com.mspbots.sync.wise.service.SurveysServiceImpl
 *
 * @author Jay.Yang
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class SurveysServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    @Override
    public Mono<Void> syncSlow(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("SURVEYS-SYNC");
        return this.get(QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("properties", properties))
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(result -> this.syncResult(properties.getTenantId(), resultSync.getRequestId(),
                        SubDataType.SURVEYS, result))
                .flatMap(result -> this.syncSurveyResults(properties, result.get("id").intValue()))
                .then();
    }

    private void syncResult(Long tenantId, UUID id, SubDataType dataType, JsonNode resultNode) {
        this.sendEntity(RabbitKeys.SUB_DATA_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(id).id(resultNode.get("id").longValue())
                .action(dataType.name()).entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }

    private Flux<JsonNode> get(QueryParams queryParams) {
        return this.cwWebClient.fetch("/service/surveys", queryParams);
    }

    private Mono<Void> syncSurveyResults(ClientProperties properties, Integer surveyId) {
        ResultSync resultSync = ResultSync.withDefault("SURVEYS-RESULTS-SYNC");
        return super.readAnchorTime(RedisKeys.SURVEYS_RESULTS_ANCHOR_REDIS_KEY_PREFIX + properties.getTenantId())
                .map(syncTime -> QueryParams.withDefault()
                        .setConditions("lastUpdated >[" + syncTime.format(DateTimeFormatter.ISO_DATE_TIME) + "]"))
                .flatMapMany(params -> this.getSurveyResults(surveyId, params))
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .contextWrite(ctx -> ctx.put("properties", properties))
                .doOnNext(resultNode -> {
                    this.syncResult(properties.getTenantId(), resultSync.getRequestId(),
                            SubDataType.SURVEYS_RESULTS, resultNode);
                    this.recordAnchorTime(RedisKeys.SURVEYS_RESULTS_ANCHOR_REDIS_KEY_PREFIX + properties.getTenantId(),
                            resultNode.findValue("lastUpdated").textValue());
                }).then();
    }

    private Flux<JsonNode> getSurveyResults(Integer surveyId, QueryParams queryParams) {
        return this.cwWebClient.fetch("/service/surveys/" + surveyId + "/results", queryParams);
    }

}
